require "trifle/ruby/app_transaction"
require "trifle/ruby/app_exception"
require "json"

module Trifle
	module Ruby
		module Middleware
			class TransactionHandler
				def initialize(app)
					@app = app
				end

				def call(env)
					transaction = AppTransaction.new(env["action_dispatch.request_id"])
					transaction.current!
					@app.call(env)
				rescue Exception => e
					environment = ::Rails.env || ENV["rack_env"] || ENV["RAILS_ENV"]
					exception_request = Rack::Request.new(env)
					exception_payload = ExceptionPayload.new( env, e,
						{
							"environment" => environment,
							"location" => self.generate_location(env),
							"session" => (env["rack.session"].to_hash rescue {}),
							"params" => location_params(env),
							"url" => exception_request.url,
							"user_agent" => env["HTTP_USER_AGENT"],
							"reference_type" => "transaction",
							"reference_id" => transaction.request_id
						}
					)
					AppException.new(exception_payload.generate!).complete!
					raise e
				ensure
					ensure_request = Rack::Request.new(env)
					request_ip = env["action_dispatch.remote_ip"].to_s.blank? ? ensure_request.ip : env["action_dispatch.remote_ip"].to_s
					unless transaction.nil?
						transaction.location = self.generate_location(env)
						transaction.user_agent = env["HTTP_USER_AGENT"]
						transaction.ipv4 = request_ip
						transaction.url = ensure_request.url
						transaction.complete! unless transaction.trace.empty?
					end
				end

				def generate_location(env)
					params = location_params(env)
					method = env["REQUEST_METHOD"]
					location = ""
					location << "[#{method}]" unless method.nil? or method.empty?
					location << "#{params["controller"]}##{params["action"]}"
					location << "(#{params["format"]})" unless params["format"].nil?
					location
				end

				def location_params(env)
					env["action_dispatch.request.parameters"] || {"controller" => "*", "action" => "*"}
				end
			end
		end
	end
end
